package tool

import (
	"fmt"
	"github.com/robfig/cron"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"math/rand"
	"net/url"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type TimerFunc func(interface{}) bool

/*
*

	delay 首次延迟
	tick 间隔
	fun 定时执行的方法
	param 方法的参数
*/
func Timer(delay, tick time.Duration, fun TimerFunc, param interface{}) {
	go func() {
		if fun == nil {
			return
		}
		t := time.NewTimer(delay)
		defer t.Stop() // 确保定时器在退出时停止

		for {
			select {
			case <-t.C:
				// 调用 safeRun，并决定是否继续执行定时器
				if !safeRun(fun, param) {
					return
				}

				// 在重置定时器前，确保没有残留事件
				if !t.Stop() {
					select {
					case <-t.C: // 清空剩余的定时器事件
					default:
					}
				}

				// 重置定时器，按照 tick 间隔继续
				t.Reset(tick)
			}
		}
	}()
}

// 安全调用 fun，防止 panic 影响计时器
func safeRun(fun TimerFunc, param interface{}) (shouldContinue bool) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("Recovered from panic: %v\n", r)
			shouldContinue = true // 即使 recover 也返回 true 以继续执行
		}
	}()

	// 调用 fun 并返回结果
	return fun(param)
}

// /添加定时任务
func AlarmTask(callback func()) {
	// 创建一个 Cron 调度器
	c := cron.New()

	// 添加一个定时任务，每天 7 点执行
	err := c.AddFunc("0 0 7 * * *", callback)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	// 启动定时任务调度器
	c.Start()
}

// / 时间戳转time.Time
func TimestampToTime(timestamp string) time.Time {
	// 转换字符串为 int64
	paySuccTimeMs, err := strconv.ParseInt(timestamp, 10, 64)
	if err != nil {
		return time.Time{}
	}

	// 转换为秒和纳秒
	seconds := paySuccTimeMs / 1000
	nanoseconds := (paySuccTimeMs % 1000) * 1000000

	// 确保纳秒在有效范围内
	if nanoseconds < 0 || nanoseconds >= 1_000_000_000 {
		nanoseconds = 0 // 或者其他适当的值
	}

	// 创建 time.Time 对象
	timeResult := time.Unix(seconds, nanoseconds)

	return timeResult
}

// 通用转换函数
func ConvertToStruct(data interface{}, result interface{}) error {
	// 将数据转换为 bson.M
	var bsonData bson.M
	switch v := data.(type) {
	case primitive.D:
		bsonData = v.Map()
	case []bson.M:
		if len(v) > 0 {
			bsonData = v[0] // 只取第一个文档
		} else {
			return fmt.Errorf("空文档")
		}
	default:
		return fmt.Errorf("不支持的数据类型")
	}

	// 将 bson.M 解码到目标结构体
	dataBytes, err := bson.Marshal(bsonData)
	if err != nil {
		return err
	}
	return bson.Unmarshal(dataBytes, result)
}

func ConvertMapInterfaceToMapString(input map[string]interface{}) (map[string]string, error) {
	output := make(map[string]string)

	for key, value := range input {
		// 使用 fmt.Sprintf 将任何类型转换为字符串
		output[key] = fmt.Sprintf("%v", value)
	}

	return output, nil
}

// 用于验证邮箱格式的正则表达式
const emailRegexPattern = `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`

// 验证邮箱格式
func IsEmailValid(email string) bool {
	re := regexp.MustCompile(emailRegexPattern)
	return re.MatchString(email)
}

// 生成随机的 Gmail 邮箱
func GenerateRandomGmail() string {
	rand.Seed(time.Now().UnixNano())
	// 生成一个随机的用户名（长度为8的随机字符）
	var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
	b := make([]rune, 8)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return fmt.Sprintf("%s@gmail.com", string(b))
}

// 生成一个随机的 10 位手机号码
func GenerateRandomPhoneNumber() string {
	rand.Seed(time.Now().UnixNano())
	// 设置手机号的前两位为99
	prefix := "99"
	// 生成后8位随机数字
	num := rand.Intn(90000000) + 10000000 // 保证是8位数字
	return prefix + strconv.Itoa(num)
}

// 检查手机号是否有效（长度是否达到10位）
func IsPhoneNumberValid(phone string) bool {
	return len(phone) == 10
}

// /  struct 转换为 map
func StructToQueryMap(s interface{}) map[string]string {
	result := make(map[string]string)
	val := reflect.ValueOf(s).Elem()
	typ := val.Type()

	for i := 0; i < val.NumField(); i++ {
		field := typ.Field(i)
		jsonTag := field.Tag.Get("json")
		if jsonTag == "" {
			jsonTag = field.Name
		}

		value := val.Field(i)
		if value.Kind() == reflect.String && value.String() != "" {
			result[jsonTag] = value.String()
		}
	}
	return result
}

// 通用的 map 获取函数
func GetStringFromMap(m map[string]any, key string) string {
	if val, ok := m[key]; ok {
		switch v := val.(type) {
		case string:
			return v
		case []byte:
			return string(v)
		case fmt.Stringer:
			return v.String()
		default:
			return fmt.Sprintf("%v", v)
		}
	}
	return ""
}

func GetUint64FromMap(m map[string]any, key string) uint64 {
	valStr := GetStringFromMap(m, key)
	num, err := strconv.ParseUint(valStr, 10, 64)
	if err != nil {
		return 0
	}
	return num
}

func StrToUint64(s string) uint64 {
	num, err := strconv.ParseUint(s, 10, 64)
	if err != nil {
		return 0
	}
	return num
}

// BuildURL 拼接基础 URL 和查询参数，返回完整 URL 字符串
func BuildURL(baseURL string, queryParams map[string]string) string {
	values := url.Values{}
	for key, val := range queryParams {
		values.Add(key, strings.TrimSpace(val))
	}
	return baseURL + "?" + values.Encode()
}
